package bioAndNio.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * @author： hmm
 * @date： 2020/7/24 10:28
 * @description： nio服务端
 * @modifiedBy： NioSocket服务端的处理过程可以分为5步：
 * 1、创建ServerSocketChannel并设置相应参数
 * 2、创建Selector并注册到ServerSocketChannel上
 * 3、调用Selector的select方法等待请求
 * 4、Selector接受到请求后使用selectedKeys返回SelectionKey集合
 * 5、使用SelectionKey获取到Channel、Selector和操作类型并进行具体操作
 */
public class NioServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(9090));
        ssc.configureBlocking(false);
        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        Handler handler = new Handler(1024);
        while(true) {
            if (selector.select(3000) == 0) {
                System.out.println("等待请求超时。。。。");
                continue;
            }
            System.out.println("处理请求。。。。。。");
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while(iterator.hasNext()) {
                SelectionKey key = iterator.next();
                try {
                    if (key.isAcceptable()) {
                        handler.handleAccept(key);
                    }
                    if (key.isReadable()) {
                        handler.handleRead(key);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    iterator.remove();
                    continue;
                }
                iterator.remove();
            }
        }
    }

    private static class Handler {
        private int bufferSize = 1024;

        private String localCharset = "UTF-8";

        public Handler() {
        }

        public Handler(int bufferSize) {
            this(bufferSize, null);
        }

        public Handler(String localCharset) {
            this(-1, localCharset);
        }

        public Handler(int bufferSize, String localCharset) {
            if (bufferSize > 0) {
                this.bufferSize = bufferSize;
            }
            if (localCharset != null) {
                this.localCharset = localCharset;
            }
        }

        public void handleAccept(SelectionKey key) throws IOException {
            SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
            channel.configureBlocking(false);
            channel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        public void handleRead(SelectionKey key) throws IOException {
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            buffer.clear();

            if (channel.read(buffer) == -1) {
                channel.close();
            } else {
                //将buffer转为读状态
                buffer.flip();
                String receivedStr = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                System.out.println("从客户端接受消息：" + receivedStr);
                String responseStr = "服务端接收到数据：" + receivedStr;
                buffer = ByteBuffer.wrap(responseStr.getBytes(localCharset));
                channel.write(buffer);
                channel.close();
            }
        }
    }
}
